using System;
using System.Security.Principal;
using System.Web;
using AndyPike.Commons.TestSupport;
using AndyPike.Snowflake.Core.Exceptions;
using AndyPike.Snowflake.Core.Services;
using AndyPike.Snowflake.Web.Controllers;
using AndyPike.Snowflake.Web.Filters;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using Rhino.Mocks;

namespace AndyPike.Snowflake.Web.Tests.Unit.Filters
{
    [TestFixture]
    public class When_calling_an_action_load_the_principle_user_if_possible : FilterUnitTestBase
    {
        private MockRepository mockery;
        private IAccountService accountService;

        [SetUp]
        public void Setup()
        {
            mockery = new MockRepository();
            accountService = mockery.DynamicMock<IAccountService>();

            filter = new LoadPrincipleFilter(accountService);

            controller = new MyController(accountService);
            PrepareController(controller, "My");
        }

        [Test]
        public void Should_allow_execution_to_continue_and_load_the_principle_if_a_valid_authentication_token()
        {
            Guid authenticationToken = Guid.NewGuid();
            bool continueExecution = false;
            var principal = mockery.Stub<IPrincipal>();

            Cookies.Add("authenticationToken", new HttpCookie("authenticationToken", authenticationToken.ToString()));

            With.Mocks(mockery)
                .Expecting(() => Expect.Call(accountService.RetrievePrincipleFromAuthenticationToken(authenticationToken)).Return(principal))
                .Verify(() => continueExecution = ExecuteFilter());

            Assert.That(continueExecution, Is.True);
            Assert.That(Context.CurrentUser, Is.EqualTo(principal));
            Assert.That(controller.PropertyBag["currentUser"], Is.EqualTo(Context.CurrentUser));
        }

        [Test]
        public void Should_allow_execution_to_continue_if_there_is_no_valid_authentication_token_cookie()
        {
            Assert.That(ExecuteFilter(), Is.True);
            Assert.That(Context.CurrentUser, Is.Null);
            Assert.That(controller.PropertyBag["currentUser"], Is.Null);
        }

        [Test]
        public void Should_allow_execution_to_continue_if_there_is_a_well_formed_but_invalid_authentication_token_cookie()
        {
            bool continueExecution = true;

            Cookies.Add("authenticationToken", new HttpCookie("authenticationToken", Guid.Empty.ToString()));

            With.Mocks(mockery)
                .Expecting(() => Expect.Call(accountService.RetrievePrincipleFromAuthenticationToken(Guid.Empty)).IgnoreArguments().Throw(new InvalidAuthenticationTokenException()))
                .Verify(() => continueExecution = ExecuteFilter());

            Assert.That(continueExecution, Is.True);
            Assert.That(Context.CurrentUser, Is.Null);
            Assert.That(controller.PropertyBag["currentUser"], Is.Null);
        }

        [Test]
        public void Should_redirect_to_the_homepage_if_there_is_a_malformed_authentication_token_cookie()
        {
            Cookies.Add("authenticationToken", new HttpCookie("authenticationToken", "a-funky-token-that-can't-be-converted-to-a-guid"));

            bool continueExecution = ExecuteFilter();

            Assert.That(continueExecution, Is.True);
            Assert.That(Context.CurrentUser, Is.Null);
            Assert.That(controller.PropertyBag["currentUser"], Is.Null);
        }
    }
}